﻿#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <vf_tcpclient.h>

namespace VFAdapter {

MyTcpClient::MyTcpClient(std::string const &msg, SelReturnData *pRtData)
    : m_sendMsg(msg), m_socket(m_ioService), m_pResData(pRtData) {}

SelReturnData MyTcpClient::StartTask(boost::asio::ip::tcp::endpoint const &ep,
                                     std::string const &msg) {
  SelReturnData rtData{3, {0}};
  ptr p_new(new MyTcpClient(msg, &rtData));
  p_new->Connect(ep);

  return rtData;
}

void MyTcpClient::Connect(boost::asio::ip::tcp::endpoint const &ep) {
  m_socket.async_connect(ep, boost::bind(&MyTcpClient::ConnectHandler,
                                         shared_from_this(),
                                         boost::placeholders::_1));
  m_ioService.run();
}

void MyTcpClient::ConnectHandler(error_code const &ec) {
  if (ec) {
    Stop();
    return;
  }
  StartSend();
}

void MyTcpClient::StartSend() {
  boost::asio::async_write(m_socket, boost::asio::buffer(m_sendMsg),
                           boost::bind(&MyTcpClient::SendHandler,
                                       shared_from_this(),
                                       boost::placeholders::_1));
}

void MyTcpClient::SendHandler(error_code const &ec) {
  if (ec) {
    Stop();
    return;
  }
  StartReceive();
}

void MyTcpClient::StartReceive() {
  memset(m_receiveBuf, 0, sizeof(m_receiveBuf));
  m_socket.async_receive(
      boost::asio::buffer(m_receiveBuf, sizeof(m_receiveBuf)),
      boost::bind(&MyTcpClient::ReceiveHandler, shared_from_this(),
                  boost::placeholders::_1));
}

void MyTcpClient::ReceiveHandler(error_code const &ec) {
  if (ec) {
    Stop();
    return;
  }
  std::string strMsg = m_receiveBuf;
  if (m_pResData != nullptr) {
    *m_pResData = SelReturnData::FromJson(strMsg);
  }
  Stop();
}

void MyTcpClient::Stop() {
  m_socket.close();
  m_ioService.stop();
}
SelFilterArg::SelFilterArg() {}
SelFilterArg::SelFilterArg(int filterType, std::string_view promptStr,
                           bool isSingleSelect)
    : m_filterType(filterType), m_isSingleSelect(isSingleSelect),
      m_promptStr(promptStr) {}

std::string SelFilterArg::ToJson() const {
  using namespace rapidjson;
  Document document;
  document.SetObject();
  document.AddMember("msgType", (int)GetMessageType(), document.GetAllocator());
  document.AddMember("type", m_filterType, document.GetAllocator());
  document.AddMember("promptStr",
                     Value().SetString(m_promptStr.data(), m_promptStr.size()),
                     document.GetAllocator());
  document.AddMember("isSingleSelect", m_isSingleSelect,
                     document.GetAllocator());

  StringBuffer buffer;
  Writer<StringBuffer> writer(buffer);
  document.Accept(writer);
  return buffer.GetString();
}

SelReturnData SelReturnData::FromJson(const std::string &json) {
  SelReturnData data{3, {}};
  try {
    using namespace rapidjson;
    std::string strJson = json;
    Document document;
    document.Parse(strJson.data());

    data.errCode = document["ErrorCode"].GetUint();
    auto idArr = document["ElementIds"].GetArray();
    for (auto &id : idArr) {
      data.ElementIds.push_back(id.GetUint());
    }
  } catch (std::exception const &e) {
    data.errCode = 3; // 3为错误的一种
  }
  return data;
}

GetMousePointArg::GetMousePointArg() {}

GetMousePointArg::GetMousePointArg(int64_t faceid) : m_faceId(faceid) {}
GetMousePointArg::GetMousePointArg(int64_t faceid, int64_t pointNum)
    : m_faceId(faceid), m_pointNum(pointNum) {}

std::string GetMousePointArg::ToJson() const {
  using namespace rapidjson;
  Document document;
  document.SetObject();
  document.AddMember("msgType", (int)GetMessageType(), document.GetAllocator());
  document.AddMember("faceId", m_faceId, document.GetAllocator());
  document.AddMember("pointNum", m_pointNum, document.GetAllocator());

  StringBuffer buffer;
  Writer<StringBuffer> writer(buffer);
  document.Accept(writer);
  return buffer.GetString();
}

GetMousePointReturnData
GetMousePointReturnData::FromJson(const std::string &json) {
  using namespace rapidjson;
  Document document;
  document.Parse(json.data());
  GetMousePointReturnData rtData;
  uint32_t errCode = document["ErrorCode"].GetUint();
  rtData.ErrorCode = errCode;

  if (0 == errCode) {
    auto arrX = document["X"].GetArray();
    for (auto const &v : arrX) {
      rtData.X.push_back(v.GetDouble());
    }
    auto arrY = document["Y"].GetArray();
    for (auto const &v : arrY) {
      rtData.Y.push_back(v.GetDouble());
    }
    auto arrZ = document["Z"].GetArray();
    for (auto const &v : arrZ) {
      rtData.Z.push_back(v.GetDouble());
    }
  }
  return rtData;
}

} // namespace VFAdapter
